package org.centsuse.intention_spring.invention.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.centsuse.intention_spring.invention.config.scenes.SceneSlotTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ChatbotUtils {
    private static final Logger logger = LoggerFactory.getLogger(ChatbotUtils.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*?\\}", Pattern.DOTALL);
    private static final Pattern FLOAT_PATTERN = Pattern.compile("-?\\d+(\\.\\d+)?");

    // 配置类
    public static class Config {
        private boolean debug;
        private String apiKey;
        private String model;
        private String gptUrl;
        private String systemPrompt;

        public boolean isDebug() {
            return debug;
        }

        public void setDebug(boolean debug) {
            this.debug = debug;
        }

        public String getApiKey() {
            return apiKey;
        }

        public void setApiKey(String apiKey) {
            this.apiKey = apiKey;
        }

        public String getModel() {
            return model;
        }

        public void setModel(String model) {
            this.model = model;
        }

        public String getGptUrl() {
            return gptUrl;
        }

        public void setGptUrl(String gptUrl) {
            this.gptUrl = gptUrl;
        }

        public String getSystemPrompt() {
            return systemPrompt;
        }

        public void setSystemPrompt(String systemPrompt) {
            this.systemPrompt = systemPrompt;
        }
    }

    // 槽位数据类
    public static class Slot {
        private String name;
        private String desc;
        private String type;
        private String value;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

    public static String filenameToClassname(String filename) {
        String[] parts = filename.split("_");
        return Arrays.stream(parts)
                .map(part -> part.substring(0, 1).toUpperCase() + part.substring(1))
                .collect(Collectors.joining());
    }

    public static Map<String, Object> loadSceneTemplates(String filePath) {
        try {
            return objectMapper.readValue(new File(filePath), new TypeReference<>() {});
        } catch (IOException e) {
            logger.error("Error loading scene templates: {}", e.getMessage());
            return Collections.emptyMap();
        }
    }

    public static Map<String, Object> loadAllSceneConfigs() throws IOException {
        Map<String, Object> allSceneConfigs = new HashMap<>();
        try (Stream<Path> paths = Files.walk(Paths.get("scene_config"))) {
            paths.filter(Files::isRegularFile)
                    .filter(path -> path.toString().endsWith(".json"))
                    .forEach(path -> {
                        Map<String, Object> config = loadSceneTemplates(path.toString());
                        config.forEach((key, value) -> allSceneConfigs.putIfAbsent(key, value));
                    });
        }
        return allSceneConfigs;
    }

    public static String sendMessage(Config config, String message, String userInput) {
        logger.info("--------------------------------------------------------------------");
        if (config.isDebug()) {
            logger.info("prompt输入: {}", message);
        } else if (userInput != null) {
            logger.info("用户输入: {}", userInput);
        }

        try (CloseableHttpClient httpClient = createUnsafeHttpClient()) {
            HttpPost httpPost = new HttpPost(config.getGptUrl());
            httpPost.setHeader("Authorization", "Bearer " + config.getApiKey());
            httpPost.setHeader("Content-Type", "application/json");

            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model", config.getModel());
            requestBody.put("messages", Arrays.asList(
                    Map.of("role", "system", "content", config.getSystemPrompt()),
                    Map.of("role", "user", "content", message)
            ));
            httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(requestBody)));

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                if (response.getStatusLine().getStatusCode() == 200) {
                    Map<String, Object> responseMap = objectMapper.readValue(
                            response.getEntity().getContent(), new TypeReference<>() {});
                    logger.info("LLM输出: {}", responseMap);
                    return ((Map<String, String>) responseMap.get("message")).get("content");
                }
            }
        } catch (Exception e) {
            logger.error("Request error: {}", e.getMessage());
        }
        return null;
    }

    private static CloseableHttpClient createUnsafeHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial((TrustStrategy) (chain, authType) -> true)
                .build();
        HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);
        return HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
    }

    public static boolean isSlotFullyFilled(Collection<SceneSlotTemplate> slots) {
        return slots != null &&
                slots.stream()
                        .filter(Objects::nonNull) // 过滤掉可能为null的slot对象
                        .map(SceneSlotTemplate::getValue)
                        .noneMatch(value ->
                                value == null ||
                                        (value instanceof String && ((String) value).isEmpty())
                        );
    }

    public static List<Slot> getRawSlot(List<Map<String, String>> parameters) {
        return parameters.stream()
                .map(param -> {
                    Slot slot = new Slot();
                    slot.setName(param.get("name"));
                    slot.setDesc(param.get("desc"));
                    slot.setType(param.get("type"));
                    slot.setValue("");
                    return slot;
                }).collect(Collectors.toList());
    }

    /**
     * 更新槽位 slot 参数
     *
     * @param jsonData   JSON 数据
     * @param dictTarget 目标字典
     */
    public static void updateSlot(List<JsonNode> jsonData, Map<String, SceneSlotTemplate> dictTarget) {
        // 遍历 JSON 数据中的每个元素
        for (JsonNode item : jsonData) {
            // 检查 value 字段是否为空字符串
            if (!item.get("value").asText().isEmpty()) {
                // 获取槽位名称
                String slotName = item.get("name").asText();
                // 在目标字典中查找匹配的槽位
                SceneSlotTemplate target = dictTarget.get(slotName);
                if (target != null) {
                    // 更新槽位的值
                    target.setValue(item.get("value").asText());
                } else {

                }
            }
        }
    }

    /**
     * JSON 抽取函数
     *
     * @param inputString 输入字符串
     * @return 包含 JSON 对象的列表
     */
    public static List<JsonNode> extractJsonFromString(String inputString) {
        List<JsonNode> validJsons = new ArrayList<>();

        try {
            // 正则表达式假设 JSON 对象由花括号括起来
            String regex = "\\{.*?\\}";
            Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
            Matcher matcher = pattern.matcher(inputString);

            while (matcher.find()) {
                String match = matcher.group();
                try {
                    // 尝试解析为 JSON 对象
                    JsonNode jsonNode = objectMapper.readTree(match);
                    validJsons.add(jsonNode);
                } catch (Exception e) {
                    try {
                        // 如果解析失败，尝试修复 JSON 字符串
                        JsonNode fixedJson = fixJson(match);
                        validJsons.add(fixedJson);
                    } catch (Exception ex) {
                        // 如果修复后仍然无效，跳过该匹配项
                        continue;
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("Error occurred: " + e.getMessage());
        }

        return validJsons;
    }

    /**
     * 修复 JSON 字符串
     *
     * @param badJson 无效的 JSON 字符串
     * @return 修复后的 JSON 对象
     */
    public static JsonNode fixJson(String badJson) {
        // 首先，用双引号替换掉所有的单引号
        String fixedJson = badJson.replace("'", "\"");

        try {
            // 然后尝试解析
            return objectMapper.readTree(fixedJson);
        } catch (JsonProcessingException e) {
            // 如果解析失败，打印错误信息，但不会崩溃
            System.err.println("给定的字符串不是有效的 JSON 格式。");
            return null;
        }
    }
}